package com.yuyou.fn.educational.service.impl;

import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.yuyou.fn.common.constant.ClassLevelEnum;
import com.yuyou.fn.common.constant.JobNatureEnum;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.educational.entity.*;
import com.yuyou.fn.educational.mapper.CourseClassMapper;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.*;
import com.yuyou.fn.platform.entity.AreaTeam;
import com.yuyou.fn.platform.entity.BusTeam;
import com.yuyou.fn.platform.permission.DataPermission;
import com.yuyou.fn.platform.service.IAreaTeamService;
import com.yuyou.fn.platform.service.IBusTeamService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * CourseClass 表数据服务层接口实现类
 */
@Service
public class CourseClassServiceImpl extends SuperServiceImpl<CourseClassMapper, CourseClass, Long> implements ICourseClassService {


    @Resource
    private IAreaTeamService areaTeamService;

    @Resource
    private IBusTeamService busTeamService;

    @Resource
    private ICourseTemplateService iCourseTemplateService;

    @Resource
    private IPeriodService periodService;

    @Resource
    private IRoomService roomService;

    @Resource
    private IRoomTimeService roomTimeService;

    @Resource
    private ITeacherService teacherService;

    @Resource
    private IClassTeacherService classTeacherService;

    @Resource
    private IClassLectureService classLectureService;

    @Resource
    private RedisTemplate redisTemplate;


    @Resource
    private IStudentRegService studentRegService;

    @Resource
    private IBaseGradeService baseGradeService;

    @Resource
    private IBaseSubjectService baseSubjectService;

    @Resource
    private ICampusService campusService;

    @Resource
    private ICourseTypeService courseTypeService;

    @Resource
    private ICourseTemplateService courseTemplateService;

    @Resource
    private IProductService productService;

    private static String[] weekNameArray = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};


    @Override
    public Page<CourseClass> findCourseClassByQueryForPage(CourseClassQueryVo courseClassQueryVo, DataPermission dataPermission, int pageNo, int pageSize) {
        Example<CourseClass> example = CourseClass.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();

        CriteriaUtils.fillConditionForBusPermission(criteria, dataPermission.getBusTeamIds());
        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);


        return findPageByExample(example, pageNo, pageSize);
    }

    @Override
    public Page<CourseClass> findByQueryForPage(List<Long> periodIds, List<Long> busTeamIds, List<Long> gradeIds, CourseClassQueryVo courseClassQueryVo, int pageNo, int pageSize) {
        Example<CourseClass> example = CourseClass.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();

        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);

        if (courseClassQueryVo.getPeriodId() == null && Utils.checkListNotEmpty(periodIds)) {
            criteria.andIn("periodId", periodIds);
        }
        if (courseClassQueryVo.getBusTeamId() == null && Utils.checkListNotEmpty(busTeamIds)) {
            criteria.andIn("busTeamId", busTeamIds);
        }
        if (courseClassQueryVo.getGradeId() == null && Utils.checkListNotEmpty(gradeIds)) {
            criteria.andIn("gradeId", gradeIds);
        }

        return findPageByExample(example, pageNo, pageSize);
    }

    @Override
    public List<CourseClass> findCourseClassList(CourseClassQueryVo courseClassQueryVo, DataPermission dataPermission, String... columns) {
        Example<CourseClass> example = CourseClass.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();

        CriteriaUtils.fillConditionForBusPermission(criteria, dataPermission.getBusTeamIds());
        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);

        if (columns != null) {
            example.selectProperties(columns);
        }

        return findListByExample(example);
    }

    @Override
    public List<CourseClass> findCourseClassByQueryForList(CourseClassQueryVo courseClassQueryVo, List<Long> areaTeamIdList, List<Long> busTeamIdList, List<Long> periodIds, List<Long> gradeIdList, String... columns) {
        Example<CourseClass> example = CourseClass.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();


        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);
        if (courseClassQueryVo.getPeriodId() == null && periodIds != null && periodIds.size() > 0) {
            criteria.andIn("periodId", periodIds);
        }
        if (courseClassQueryVo.getAreaTeamId() == null && areaTeamIdList != null && areaTeamIdList.size() > 0) {
            criteria.andIn("areaTeamId", areaTeamIdList);
        }
        if (courseClassQueryVo.getBusTeamId() == null && busTeamIdList != null && busTeamIdList.size() > 0) {
            criteria.andIn("busTeamId", busTeamIdList);
        }
        if (courseClassQueryVo.getGradeId() == null && gradeIdList != null && gradeIdList.size() > 0) {
            criteria.andIn("gradeId", gradeIdList);
        }
        if (columns != null) {
            example.selectProperties(columns);
        }

        example.orderBy("areaTeamId");
        example.orderBy("busTeamId");
        example.orderBy("periodId");

        return findListByExample(example);

    }

    @Transactional
    @Override
    public CourseClass saveOrUpdateCourseClass(CourseClassSaveOrUpdateVo courseClassSaveOrUpdateVo) {

        CourseClass courseClass = new CourseClass();

        BeanUtils.copyProperties(courseClass, courseClassSaveOrUpdateVo);
        fillExtraData(courseClass);

        checkClassName(courseClass);

        if (courseClass.getClassId() == null) {
            courseClass.setProgressStatus(0);
            courseClass.setClassNo(createClassNo());
            courseClass.setCreateTime(TimeUtils.now());
            courseClass.setUpdateTime(TimeUtils.now());
            insertSelective(courseClass);
            classLectureService.createClassLecture(courseClass.getClassId(), courseClass.getLectureAmount());
        } else {

            //CourseClass oldCourseClass = findById(courseClass.getClassId());
            /*if (oldCourseClass.getLectureAmount().intValue() != courseClass.getLectureAmount().intValue()) {//修改了讲数
                //要重排时间
                prepareRearrange(courseClass.getClassId(), 1);
                //重新调整classLecture
                classLectureService.updateClassLecture(courseClass.getClassId(), courseClass.getLectureAmount());
            }*/

            //这些字段不能更新
            //  courseClass.setLectureAmount(null);
            CourseClass oldCourseClass = findById(courseClass.getClassId());
            if (!oldCourseClass.getQuota().equals(courseClassSaveOrUpdateVo.getQuota())){
                courseClass.setDegreeUpdateTime(TimeUtils.now());
            }
            courseClass.setLectureDuration(null);
            courseClass.setMaterialFee(null);
            courseClass.setSubjectId(null);
            courseClass.setSubjectName(null);
            courseClass.setGradeId(null);
            courseClass.setGradeName(null);
            courseClass.setProductId(null);

            courseClass.setCourseTemplateId(null);

            courseClass.setUpdateTime(TimeUtils.now());
            updateSelectiveById(courseClass);


        }
        return courseClass;
    }

    private String createClassNo() {
        Long no = redisTemplate.opsForValue().increment("class_no", 1);
        return StringUtils.leftPad(String.valueOf(no), 6, "0");
    }

    private void checkClassName(CourseClass courseClass) {
        /*Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("periodId", courseClass.getPeriodId() ).andEqualTo("className",courseClass.getClassName()) ;

        CourseClass one = findOneByExample(example);

        if(one != null && ( courseClass.getClassId() == null || !one.getClassId().equals(courseClass.getClassId()))){
            throw new BusException("同一期班名重复");
        }*/
    }

    private void fillExtraData(CourseClass courseClass) {

        if (courseClass.getAreaTeamId() != null) {
            courseClass.setAreaTeamName(areaTeamService.findTeamNameById(courseClass.getAreaTeamId()));
        } else {
            courseClass.setAreaTeamId(0l);
            courseClass.setAreaTeamName("");
        }

        if (courseClass.getBusTeamId() != null) {
            courseClass.setBusTeamName(busTeamService.findTeamNameById(courseClass.getBusTeamId()));
        } else {
            courseClass.setBusTeamId(0l);
            courseClass.setBusTeamName("");
        }


        if (courseClass.getPeriodId() != null && periodService.findById(courseClass.getPeriodId()) != null) {
            Period period = periodService.findById(courseClass.getPeriodId(), "periodName");
            courseClass.setPeriodName(period.getPeriodName());
        } else {
            courseClass.setPeriodId(0l);
            courseClass.setPeriodName(StringUtils.EMPTY);
        }

        if (courseClass.getCourseTemplateId() != null) {
            CourseTemplate courseTemplate = iCourseTemplateService.findById(courseClass.getCourseTemplateId());
            if (courseTemplate != null) {
                //courseClass.setLectureAmount(courseTemplate.getLectureAmount());
                courseClass.setLectureDuration(courseTemplate.getLectureDuration());
                courseClass.setMaterialFee(courseTemplate.getMaterialFee());
                courseClass.setSubjectId(courseTemplate.getSubjectId());
                courseClass.setSubjectName(courseTemplate.getSubjectName());
                courseClass.setGradeId(courseTemplate.getGradeId());
                courseClass.setGradeName(courseTemplate.getGradeName());
                courseClass.setProductId(courseTemplate.getProductId());
                //courseClass.setLevel(courseTemplate.getLevel());
            }
        } else {
            courseClass.setCourseTemplateId(0l);
            courseClass.setLectureAmount(0);
            courseClass.setLectureDuration(0);
            courseClass.setStudyingFee(new BigDecimal(0));
            courseClass.setMaterialFee(new BigDecimal(0));
            courseClass.setSubjectId(0l);
            courseClass.setSubjectName("");
            courseClass.setGradeId(0l);
            courseClass.setGradeName("");
            courseClass.setLevel(1);
        }

        if (courseClass.getCampusId() != null) {
            courseClass.setCampusName(campusService.findById(courseClass.getCampusId(), "campusName").getCampusName());
        }

    }


    @Transactional
    @Override
    public void saveArrangementRoom(Long classId, Long roomId) {
        roomTimeService.detectConflict(classId, roomId);
        CourseClass courseClass = new CourseClass();
        courseClass.setClassId(classId);
        courseClass.setRoomId(roomId);
        Room room = roomService.findById(roomId);
        courseClass.setCampusId(room.getCampusId());
        courseClass.setCampusName(room.getCampusName());
        courseClass.setRoomName(room.getRoomName());
        courseClass.setIsArrangeRoom(1);
        courseClass.setUpdateTime(TimeUtils.now());
        updateSelectiveById(courseClass);
        roomTimeService.saveOrUpdateRoomTime(classId);
    }

    @Transactional
    @Override
    public void saveArrangementTeacher(Long classId, List<Long> teacherIds) {
        if (classId == null || teacherIds == null) throw new BusException("班级id或者教师id为空");

        classLectureService.saveArrangementTeacher(classId, teacherIds);
        classTeacherService.saveTeachers(classId, teacherIds, 2);//任课老师


        Teacher mainTeacher = getMainTeacher(classLectureService.findClassLectureByClassId(classId));
        CourseClass courseClass = new CourseClass();
        courseClass.setClassId(classId);
        setCourseTeacherIds(teacherIds, courseClass);
        courseClass.setTeacherId(mainTeacher.getTeacherId());
        courseClass.setTeacherName(mainTeacher.getTeacherName());
        courseClass.setJobNature(mainTeacher.getJobNature());
        courseClass.setIsArrangeTeacher(1);
        courseClass.setUpdateTime(TimeUtils.now());
        updateSelectiveById(courseClass);
    }

    private void setCourseTeacherIds(List<Long> teacherIds, CourseClass courseClass) {
        List<Teacher> teacherList = teacherService.findByIds(teacherIds);
        List<Long> teacherIdList = new ArrayList<>(2);
        List<String> teacherNameList = new ArrayList<>(2);
        for (Teacher t : teacherList) {
            teacherIdList.add(t.getTeacherId());
            teacherNameList.add(t.getTeacherName());
        }
        courseClass.setTeacherIds(StringUtils.join(teacherIdList, ","));
        courseClass.setTeacherNames(StringUtils.join(teacherNameList, ","));
    }


    @Override
    public boolean decreaseRegAmount(Long classId) {
        return autoMapper.decreaseRegAmount(classId) > 0;
    }


    @Transactional
    @Override
    public void saveArrangeClassTimeResult(Long classId, List<ArrangeClassTimeResultVo> arrangeClassTimeResultList) {
        classLectureService.saveArrangeClassTimeResult(classId, arrangeClassTimeResultList);

        Set<String> times = new HashSet<>();
        for (ArrangeClassTimeResultVo vo : arrangeClassTimeResultList) {
            times.add(vo.getTime());
        }

        CourseClass courseClass = new CourseClass();
        courseClass.setClassId(classId);
        courseClass.setIsArrangeTime(1);
        courseClass.setStudyingTime(StringUtils.join(times, " "));
        courseClass.setStartCourseTime(TimeUtils.parse(arrangeClassTimeResultList.get(0).getDate(), "yyyy-MM-dd"));
        courseClass.setEndCourseTime(TimeUtils.parse(arrangeClassTimeResultList.get(arrangeClassTimeResultList.size() - 1).getDate(), "yyyy-MM-dd"));
        courseClass.setClassDateTip(classDateTip(arrangeClassTimeResultList));
        courseClass.setUpdateTime(TimeUtils.now());
        this.updateSelectiveById(courseClass);
    }

    private String classDateTip(List<ArrangeClassTimeResultVo> arrangeClassTimeResultList) {
        if (arrangeClassTimeResultList.size() <= 1) {
            return StringUtils.EMPTY;
        }
        Date d1 = TimeUtils.parse(arrangeClassTimeResultList.get(0).getDate(), "yyyy-MM-dd");
        Date d2 = TimeUtils.parse(arrangeClassTimeResultList.get(1).getDate(), "yyyy-MM-dd");
        int offset = d2.getDate() - d1.getDate();
        if (offset <= 0) {
            return StringUtils.EMPTY;
        } else if (offset == 1) {
            return "每天";
        } else if (offset == 7) {
            return new SimpleDateFormat("E", Locale.CHINA).format(d1).replace("星期", "每周");
        } else {
            return StringUtils.EMPTY;
        }
    }


    @Override
    public void changeStatus(final List<Long> classIds, Integer status) {

        if (status == 1 || status == 2) {
            List<CourseClass> courseClassList = findByIds(classIds);

            for (CourseClass courseClass : courseClassList) {
                if (courseClass.getStatus() == 2) {
                    throw new BusException("【" + courseClass.getClassName() + "】已作废，不能更改");
                }
                if (status == 1) {
                    if (courseClass.getIsArrangeTime() == 0) {
                        throw new BusException("【" + courseClass.getClassName() + "】未排时间，不能开班");
                    }
                } else if (status == 2) {
                    if (courseClass.getClassType() == 0) {
                        if (courseClass.getRegAmount() > 0) {
                            throw new BusException("【" + courseClass.getClassName() + "】有报名学生，不能作废");
                        }
                    } else if (courseClass.getClassType() == 1) {

                    }

                }
            }
        }

        Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("classId", classIds);
        CourseClass update = new CourseClass();
        update.setStatus(status);
        update.setUpdateTime(TimeUtils.now());
        updateSelectiveByExample(update, example);

        if (status == 2) {
            Threads.delay(new Runnable() {
                @Override
                public void run() {

                    for (Long classId : classIds) {
                        prepareRearrangeTeacher(classId);
                        prepareRearrangeRoom(classId);
                        prepareRearrangeClassTime(classId);
                    }
                }
            }, 1);
        }
    }

    @Override
    public boolean increaseRegAmount(Long classId, Integer nowRegAmount) {
        return autoMapper.increaseRegAmount(classId) > 0;
    }

    @Override
    public boolean updateCompletedLectureAmount(Long classId, Integer completedLectureAmount) {
        CourseClass update = new CourseClass();
        update.setCompletedLectureAmount(completedLectureAmount);
        update.setProgressStatus(1);
        update.setUpdateTime(TimeUtils.now());

        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andEqualTo("classId", classId).andEqualTo("completedLectureAmount", completedLectureAmount - 1);
        return updateSelectiveByExample(update, example);
    }

    @Override
    public void recommendCourseClass(List<Long> classIds, Integer isRecommend) {
        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andIn("classId", classIds);
        CourseClass update = new CourseClass();
        update.setIsRecommend(isRecommend);
        update.setUpdateTime(TimeUtils.now());
        updateSelectiveByExample(update, example);
    }

    @Override
    public Page<CourseClass> findMyTeachingCourseClass(Long teacherId, Long periodId, int pageNo, int pageSize) {

        Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andLike("teacherIds", "%" + teacherId + "%");
        criteria.andEqualTo("periodId", periodId);
        example.orderBy("startCourseTime").orderBy("startTime");
        return findPageByExample(example, pageNo, pageSize);
    }


    @Override
    public List<CourseClass> findCourseClassByPeriodIdTeacherId(Long periodId, Long teacherId) {
        Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("periodId", periodId);
        criteria.andNotEqualTo("status", 0).andNotEqualTo("status", "2");
        criteria.andLike("teacherIds", "%" + teacherId + "%");
        return findListByExample(example);
    }

    @Override
    public List<CourseClass> findUseCourseClassByPeriodIds(List<Long> periodIds,String ...columns) {
        if (Utils.checkListEmpty(periodIds)){
            return Collections.EMPTY_LIST;
        }
        Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("periodId", periodIds);
        criteria.andNotEqualTo("status", "2");
        if (columns!=null){
            example.selectProperties(columns);
        }
        return findListByExample(example);
    }

    @Override
    public List<CourseClass> suggestCourseClassForTeacher(Long periodId, Long teacherId, int limit) {
        //同年级，其他科目
        Teacher teacher = teacherService.findById(teacherId);
        Example<CourseClass> example = CourseClass.createExample();
        example.limit(limit);
        Example.Criteria criteria = example.createCriteria();
        criteria.andNotLike("teacherIds", "%" + teacherId + "%");//非我的
        criteria.andEqualTo("periodId", periodId);
        criteria.andNotEqualTo("status", 0).andNotEqualTo("status", "2");
        criteria.andIn("gradeId", Utils.toLongIds(teacher.getTeachGradeIds()));
        criteria.andNotIn("subjectId", Utils.toLongIds(teacher.getTeachSubjectIds()));
        return findListByExample(example);
    }

    @Transactional
    @Override
    public void prepareRearrange(Long classId, Integer which) {

        CourseClass courseClass = findById(classId);

        if (which != 2 && courseClass.getProgressStatus() != null && courseClass.getProgressStatus() != 0) {
            throw new BusException("已经开始授课，无法重排或释放");
        }

        //which 1重排时间 2重排课室 3重排老师
        if (which == 1) {
            //prepareRearrangeTeacher(classId);
            // prepareRearrangeRoom(classId);
            prepareRearrangeClassTime(classId);
        }

        if (which == 2) {
            prepareRearrangeRoom(classId);
        }

        if (which == 3) {
            prepareRearrangeTeacher(classId);
        }
    }

    private void prepareRearrangeClassTime(Long classId) {
        classLectureService.clearClassTime(classId);
        //autoMapper.clearClassTime(classId);
    }

    private void prepareRearrangeRoom(Long classId) {

        autoMapper.clearRoom(classId);
        roomTimeService.clearRoomTime(classId);


    }

    private void prepareRearrangeTeacher(Long classId) {


        this.clearTeacher(classId);
        classLectureService.clearTeacher(classId);
        classTeacherService.clearTeacher(classId);

    }

    @Override
    @Transactional
    public void rearrangeTeacherForLecture(final Long classLectureId, Long teacherId, boolean updateAfterLecture, String remark) {
        classLectureService.rearrangeTeacherForLecture(classLectureId, teacherId, updateAfterLecture, remark);
        Threads.delay(new Runnable() {
            @Override
            public void run() {
                ClassLecture classLecture = classLectureService.findById(classLectureId);
                updateTeacherInfo(classLecture.getClassId());

            }
        }, 1);
    }

    @Override
    @Transactional
    public void reArrangeTeacherForLectures(Long classLectureId, Long teacherId, String remark) {
        ClassLecture currentClassLecture = classLectureService.findById(classLectureId);
        Long classId = currentClassLecture.getClassId();
        Example<ClassLecture> example = ClassLecture.createExample();
        example.orderBy("lectureNo");
        example.createCriteria().andEqualTo("classId",classId).
                andGreaterThanOrEqualTo("lectureNo",currentClassLecture.getLectureNo());
        List<ClassLecture> classLectures = classLectureService.findListByExample(example);
        classLectureService.reArrangeTeacherForLectrues(classLectures,teacherId,remark);
        Threads.delay(new Runnable() {
            @Override
            public void run() {
                updateTeacherInfo(currentClassLecture.getClassId());

            }
        }, 1);
    }

    public void updateTeacherInfo(Long classId) {
        List<ClassLecture> classLectureList = classLectureService.findClassLectureByClassId(classId);

        Teacher teacher = getMainTeacher(classLectureList);

        CourseClass update = new CourseClass();
        update.setClassId(classId);
        setCourseTeacherIds(Utils.unique(BeanUtils.toList(classLectureList, "teacherId")), update);
        update.setTeacherId(teacher.getTeacherId());
        update.setTeacherName(teacher.getTeacherName());
        update.setJobNature(teacher.getJobNature());
        update.setIsArrangeTeacher(1);
        update.setUpdateTime(TimeUtils.now());
        updateSelectiveById(update);

        classTeacherService.clearTeacher(classId);

        List<Long> teacherIds = BeanUtils.toList(classLectureList, "teacherId");
        classTeacherService.saveTeachers(classId, Utils.unique(teacherIds), 2);

    }

    /**
     * 获取主讲老师
     *
     * @param classLectureList
     * @return
     */
    private Teacher getMainTeacher(List<ClassLecture> classLectureList) {
        Map<Long, Integer> counter = new LinkedHashMap<>();

        for (ClassLecture classLecture : classLectureList) {
            Integer c = counter.get(classLecture.getTeacherId());
            if (c == null) {
                c = Integer.valueOf(0);
            }
            c++;
            counter.put(classLecture.getTeacherId(), c);
        }

        Long teacherId = classLectureList.get(0).getTeacherId();
        for (Map.Entry<Long, Integer> entry : counter.entrySet()) {
            if (!entry.getKey().equals(teacherId)) {
                if (counter.get(teacherId) < entry.getValue()) {
                    teacherId = entry.getKey();
                }
            }
        }
        return teacherService.findById(teacherId);
    }

    @Override
    public void rearrangeTimeForLecture(Long classLectureId, String date, String time, boolean updateAfterLecture) {
        classLectureService.rearrangeTimeForLecture(classLectureId, date, time, updateAfterLecture);
    }

    @Override
    public Page<CourseClass> findCourseClassByQuery(CourseClassQueryVo courseClassQueryVo, int pageNo, int pageSize) {
        Example<CourseClass> example = CourseClass.createExample();
        if (courseClassQueryVo.getOrderByStartCourseTime()) {
            example.orderBy("startCourseTime");
        } else {
            example.orderBy("createTime").desc();
        }

        Example.Criteria criteria = example.createCriteria();

        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);

        return findPageByExample(example, pageNo, pageSize);

    }

    public List<CourseClass> findByTeacherIdAndStatusAndProgressStatus(Long teacherId, Integer status, Integer progressStatus) {
        Example<CourseClass> courseClassExample = CourseClass.createExample();
        Example.Criteria criteria = courseClassExample.createCriteria();
        criteria.andEqualTo("status", status);
        criteria.andEqualTo("progressStatus", progressStatus);
        criteria.andLike("teacherIds", "%" + teacherId + "%");

        return findListByExample(courseClassExample);
    }


    @Transactional
    @Override
    public void saveClassChange(final Long classId, String className, String studyingTime, Long teacherId) {

        CourseClass courseClass = findById(classId);

        if (courseClass.getProgressStatus() != 0) {
            throw new BusException("已开课不能调整");
        }

        if (className != null || studyingTime != null) {
            CourseClass update = new CourseClass();
            update.setClassId(classId);
            update.setClassName(className);
            update.setStudyingTime(studyingTime);
            update.setUpdateTime(TimeUtils.now());
            updateSelectiveById(update);
        }

        if (studyingTime != null) {
            classLectureService.updateTime(classId, studyingTime);
        }

        if (teacherId != null) {
            classLectureService.updateTeacher(classId, teacherId);
            Threads.delay(new Runnable() {
                @Override
                public void run() {
                    updateTeacherInfo(classId);
                }
            }, 1);
        }
    }


    @Override
    public List<CourseClass> findByClassNo(List<String> classNos) {
        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andIn("classNo", classNos);
        return findListByExample(example);
    }


    @Override
    public List<CourseClass> findSimpByProductIds(List<Long> productIds, String... columns) {
        if (productIds == null || productIds.size() <= 0) {
            return Collections.EMPTY_LIST;
        }
        Example example = CourseClass.createExample();
        example.selectProperties(columns);

        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("productId", productIds).andNotEqualTo("status", 2);
        return findListByExample(example);
    }


    @Override
    public List<CourseClass> findSimpByProductIdsAndBusTeamIdsAndPeriodId(List<Long> productIds, List<Long> busTeamIds, Long periodId, String... columns) {
        if (productIds == null || productIds.size() <= 0 || busTeamIds == null || busTeamIds.size() <= 0) {
            return Collections.EMPTY_LIST;
        }
        Example example = CourseClass.createExample();
        example.selectProperties(columns);

        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("productId", productIds);
        criteria.andIn("busTeamId", busTeamIds);
        criteria.andNotEqualTo("status", 2);
        criteria.andEqualTo("periodId", periodId);
        return findListByExample(example);

    }


    @Override
    public List<CourseClass> findSimpByBusTeamIds(List<Long> busTeamIdList, String... columns) {

        if (busTeamIdList == null || busTeamIdList.size() <= 0) {
            return Collections.EMPTY_LIST;
        }

        Example example = CourseClass.createExample();
    /*    example.selectProperties("classId","className","gradeId","gradeName","subjectId","subjectName","regAmount","areaTeamId","busTeamId",
                "areaTeamName","busTeamName","studyingFee","productId","lectureAmount"
        );*/
        example.selectProperties(columns);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("busTeamId", busTeamIdList);
        criteria.andNotEqualTo("status", 2);

        return findListByExample(example);
    }

    @Override
    public List<CourseClass> findSimpByBusTeamIdsAndPeriodId(List<Long> busTeamIdList, Long periodId, String... columns) {
        if (busTeamIdList == null || busTeamIdList.size() <= 0) {
            return Collections.EMPTY_LIST;
        }

        Example example = CourseClass.createExample();
    /*    example.selectProperties("classId","className","gradeId","gradeName","subjectId","subjectName","regAmount","areaTeamId","busTeamId",
                "areaTeamName","busTeamName","studyingFee","productId","lectureAmount"
        );*/
        example.selectProperties(columns);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("busTeamId", busTeamIdList);
        criteria.andNotEqualTo("status", 2);
        criteria.andEqualTo("periodId", periodId);
        return findListByExample(example);
    }


    @Override
    @Cacheable("CacheOfBaseCourseClassByGradeIdsAndSubjectIds")
    public List<CourseClass> findByBusTeamIdsAndGradesAndSubjects(List<Long> busTeamIdList, List<Long> gradeIds, List<Long> subjectIds, String... columns) {
        Example example = CourseClass.createExample();
        if (columns != null) {
            example.selectProperties(columns);
        }
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("busTeamId", busTeamIdList);
        criteria.andIn("gradeId", gradeIds);
        criteria.andIn("subjectId", subjectIds);
        criteria.andNotEqualTo("status", 2);
        return findListByExample(example);
    }


    @Override
    @Transactional
    public void updateSenior(final Long[] classIds, final Long teacherId) {

        final Teacher teacher = teacherService.findById(teacherId);
        teacher.getTeacherName();

        CourseClass update = new CourseClass();
        update.setSeniorId(teacherId);
        update.setSeniorName(teacher.getTeacherName());
        update.setUpdateTime(TimeUtils.now());
        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andIn("classId", Arrays.asList(classIds));

        updateSelectiveByExample(update, example);

        Threads.dispatch(new Runnable() {
            @Override
            public void run() {
                studentRegService.updateSenior(Arrays.asList(classIds), teacherId, teacher.getTeacherName());
            }
        });


    }

    @Cacheable("CacheOfBaseCourseClassByProductId")
    @Override
    public List<CourseClass> findBaseCourseClassByProductIds(List<Long> productIdList, String... props) {
        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andIn("productId", productIdList).andNotEqualTo("status", 2);
        example.selectProperties(props);
        return findListByExample(example);
    }

    @Cacheable("CacheOfBaseCourseClassByBusTeamId")
    @Override
    public List<CourseClass> findBaseCourseClassByBusTeamIds(List<Long> busTeamIdList, String... props) {
        Example<CourseClass> example = CourseClass.createExample();
        example.createCriteria().andIn("busTeamId", busTeamIdList).andNotEqualTo("status", 2);
        example.selectProperties(props);
        return findListByExample(example);
    }



    @Override
    public void importCourseClass(List<ImportCourseClassVo> importCourseClassVoList) throws Exception {
        validateImportClass(importCourseClassVoList);

        LoadingCache<String, Optional<AreaTeam>> areaTeamCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<AreaTeam>>() {
            @Override
            public Optional<AreaTeam> load(String key) throws Exception {
                return Optional.fromNullable(areaTeamService.findAreaTeamByName(key));
            }
        });

        LoadingCache<String, Optional<BusTeam>> busTeamCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<BusTeam>>() {
            @Override
            public Optional<BusTeam> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                return Optional.fromNullable(busTeamService.findByAreaTeamIdAndBusName(Long.valueOf(keyParts[0]), keyParts[1]));
            }
        });

        LoadingCache<String, Optional<Period>> periodCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<Period>>() {
            @Override
            public Optional<Period> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                return Optional.fromNullable(periodService.findPeriodByAreaTeamIdPeriodName(Long.valueOf(keyParts[0]), keyParts[1]));
            }
        });


        LoadingCache<String, Optional<CourseType>> courseTypeCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<CourseType>>() {
            @Override
            public Optional<CourseType> load(String key) throws Exception {
                return Optional.fromNullable(courseTypeService.findCourseTypeByName(key));
            }
        });

        LoadingCache<String, Optional<CourseTemplate>> courseTemplateCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<CourseTemplate>>() {
            @Override
            public Optional<CourseTemplate> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                CourseTemplate courseTemplate = courseTemplateService.findCourseByAreaTeamIdGradeIdSubjectIdCourseNamePeriodIdProductId(Long.valueOf(keyParts[0]), Long.valueOf(keyParts[1]), Long.valueOf(keyParts[2]), keyParts[3], Long.valueOf(keyParts[4]), Long.valueOf(keyParts[5]));
                return Optional.fromNullable(courseTemplate);
            }
        });

        LoadingCache<String, Optional<Product>> productCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<Product>>() {
            @Override
            public Optional<Product> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                Product product = productService.findProductByNameAreaTeamId(keyParts[1], Long.valueOf(keyParts[0]));
                return Optional.fromNullable(product);
            }
        });

        LoadingCache<String, Optional<BaseGrade>> gradeCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<BaseGrade>>() {
            @Override
            public Optional<BaseGrade> load(String key) throws Exception {
                return Optional.fromNullable(baseGradeService.findGradeByGradeName(key));
            }
        });

        LoadingCache<String, Optional<BaseSubject>> subjectCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<BaseSubject>>() {
            @Override
            public Optional<BaseSubject> load(String key) throws Exception {
                return Optional.fromNullable(baseSubjectService.findSubjectBySubjectName(key));
            }
        });

        LoadingCache<String, Optional<Campus>> campustCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<Campus>>() {
            @Override
            public Optional<Campus> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                return Optional.fromNullable(campusService.findCampusByAreaTeamIdCampusName(Long.valueOf(keyParts[0]), keyParts[1]));
            }
        });

        LoadingCache<String, Optional<Teacher>> teacherCache = CacheBuilder.newBuilder().build(new CacheLoader<String, Optional<Teacher>>() {
            @Override
            public Optional<Teacher> load(String key) throws Exception {
                String[] keyParts = key.split("#");
                return Optional.fromNullable(teacherService.findTeacherByAreaTeamIdTeacherName(Long.valueOf(keyParts[0]), keyParts[1]));
            }
        });


        Map<String, Integer> segmentMap = new HashMap<>();
        segmentMap.put("段次1", 1);
        segmentMap.put("段次2", 2);
        segmentMap.put("段次3", 3);
        segmentMap.put("段次4", 4);
        segmentMap.put("段次5", 5);

        Date now = TimeUtils.now();
        List<ClassLecture> allClassLectureList = new ArrayList<>(importCourseClassVoList.size() * 10);
        List<CourseClass> courseClassList = new ArrayList<>(importCourseClassVoList.size());
        List<ClassTeacher> classTeacherList = new ArrayList<>(importCourseClassVoList.size());
        for (ImportCourseClassVo importCourseClassVo : importCourseClassVoList) {
            Optional<AreaTeam> areaTeamOptional = areaTeamCache.get(importCourseClassVo.getAreaTeamName());
            if (!areaTeamOptional.isPresent()) {
                throw new BusException("无法匹配系统区域:" + importCourseClassVo.getAreaTeamName());
            }
            AreaTeam areaTeam = areaTeamOptional.get();

            Optional<BusTeam> busTeamOptional = busTeamCache.get(String.valueOf(areaTeam.getAreaTeamId()) + "#" + importCourseClassVo.getBusTeamName());

            if (!busTeamOptional.isPresent()) {
                throw new BusException("无法匹配系统业务组:" + importCourseClassVo.getBusTeamName());
            }

            BusTeam busTeam = busTeamOptional.get();

            Optional<Period> periodOptional = periodCache.get(String.valueOf(areaTeam.getAreaTeamId()) + "#" + importCourseClassVo.getYear() + importCourseClassVo.getSeason());

            if (!periodOptional.isPresent()) {
                throw new BusException("无法匹配系统季节:" + importCourseClassVo.getYear() + importCourseClassVo.getSeason());
            }

            Period period = periodOptional.get();

            Optional<CourseType> courseTypeOptional = courseTypeCache.get(importCourseClassVo.getCourseType());

            if (!courseTypeOptional.isPresent()) {
                throw new BusException("无法匹配系统课程类型:" + importCourseClassVo.getCourseType());
            }

            CourseType courseType = courseTypeOptional.get();

            Optional<BaseGrade> baseGradeOptional = gradeCache.get(importCourseClassVo.getGradeName());
            if (!baseGradeOptional.isPresent()) {
                throw new BusException("无法匹配系统年级:" + importCourseClassVo.getGradeName());
            }

            BaseGrade baseGrade = baseGradeOptional.get();

            Optional<BaseSubject> baseSubjectOptional = subjectCache.get(importCourseClassVo.getSubjectName());
            if (!baseSubjectOptional.isPresent()) {
                throw new BusException("无法匹配系统科目:" + importCourseClassVo.getGradeName());
            }

            Optional<Campus> campusOptional = campustCache.get(areaTeam.getAreaTeamId() + "#" + importCourseClassVo.getCampusName());
            if (!campusOptional.isPresent()) {
                throw new BusException("无法匹配系统校区:" + importCourseClassVo.getCampusName());
            }


            Optional<Teacher> teacherOptional = null;
            if (!StringUtils.isEmpty(importCourseClassVo.getTeacherName())) {
                teacherOptional = teacherCache.get(areaTeam.getAreaTeamId() + "#" + importCourseClassVo.getTeacherName());
                if (!teacherOptional.isPresent()) {
                    throw new BusException("无法匹配系统任课老师:" + importCourseClassVo.getTeacherName());
                }
            }

            if (period.getSegments() < segmentMap.get(importCourseClassVo.getSegment())) {
                throw new BusException("段次超出系统设置:" + period.getPeriodName() + "最大段次是" + period.getSegments());
            }

            Long teacherId = null;
            String teacherName = null;
            Integer jobNature = null;
            if (null != teacherOptional) {
                Teacher teacher = teacherOptional.get();
                teacherId = teacher.getTeacherId();
                teacherName = teacher.getTeacherName();
                jobNature = teacher.getJobNature();
            }

            BaseSubject baseSubject = baseSubjectOptional.get();

            Optional<Product> productOptional = productCache.get(String.valueOf(areaTeam.getAreaTeamId()) + "#" + importCourseClassVo.getProductName());

            if (!productOptional.isPresent()) {
                Product product = createProduct(now, importCourseClassVo, areaTeam);
                productOptional = Optional.of(product);
                productCache.invalidate(String.valueOf(areaTeam.getAreaTeamId()) + "#" + importCourseClassVo.getProductName());

            }


            Product product = productOptional.get();
            Optional<CourseTemplate> courseTemplateOptional = courseTemplateCache.get(String.valueOf(areaTeam.getAreaTeamId()) + "#" + baseGrade.getGradeId() + "#" + baseSubject.getSubjectId() + "#" + importCourseClassVo.getCourseName() + "#" + period.getPeriodId() +"#" + product.getProductId());

            if (!courseTemplateOptional.isPresent()) {
                CourseTemplate courseTemplate = createCourseTemplate(now, importCourseClassVo, areaTeam, busTeam, courseType, baseGrade, baseSubject, product, period);
                courseTemplateOptional = Optional.of(courseTemplate);
                courseTemplateCache.invalidate(String.valueOf(areaTeam.getAreaTeamId()) + "#" + baseGrade.getGradeId() + "#" + baseSubject.getSubjectId() + "#" + importCourseClassVo.getCourseName() + "#" + period.getPeriodId() +"#" + product.getProductId());
            }

            CourseTemplate courseTemplate = courseTemplateOptional.get();
            CourseClass courseClass = new CourseClass();
            BeanUtils.copyProperties(courseClass, courseTemplate);

            courseClass.setClassId(IdWorker.getId());
            courseClass.setStatus(0);
            courseClass.setIsArrangeTime(0);
            courseClass.setIsArrangeRoom(0);
            //courseClass.setIsArrangeTeacher(0);
            courseClass.setClassNo(createClassNo());
            courseClass.setRegAmount(0);
            courseClass.setProgressStatus(0);
            courseClass.setStudyingFee(importCourseClassVo.getStudyingFee());
            courseClass.setLectureAmount(importCourseClassVo.getLectureAmount());
            courseClass.setLectureDuration(importCourseClassVo.getLectureDuration());
            courseClass.setLevel(EnumUtils.valueOf(ClassLevelEnum.values(), importCourseClassVo.getLevel()).ordinal());
            courseClass.setClassName(importCourseClassVo.getClassName());
            courseClass.setClassAliasName(StringUtils.isNotEmpty(importCourseClassVo.getClassAliasName())?importCourseClassVo.getClassAliasName():importCourseClassVo.getClassName());
            courseClass.setUpdateTime(now);
            courseClass.setCreateTime(now);
            courseClass.setCompletedLectureAmount(0);
            courseClass.setClassType(0);
            courseClass.setPeriodId(period.getPeriodId());
            courseClass.setPeriodName(period.getPeriodName());
            courseClass.setQuota(importCourseClassVo.getQuota());
            courseClass.setSegmentNo(segmentMap.get(importCourseClassVo.getSegment()));
            courseClass.setIsRecommend(0);
            courseClass.setBusTeamName(busTeam.getName());
            courseClass.setBusTeamId(busTeam.getBusTeamId());
            courseClass.setCampusId(campusOptional.get().getCampusId());
            courseClass.setCampusName(campusOptional.get().getCampusName());

            List<ClassLecture> classLectureList = buildClassLecture(now, importCourseClassVo, courseClass, teacherId, teacherName);
            allClassLectureList.addAll(classLectureList);

            courseClass.setIsArrangeTime(1);
            if ("每天".equals(importCourseClassVo.getClassPeriod())) {
                courseClass.setClassDateTip(importCourseClassVo.getClassPeriod());
            } else if ("每周".equals(importCourseClassVo.getClassPeriod())) {
                courseClass.setClassDateTip(new SimpleDateFormat("E", Locale.CHINA).format(importCourseClassVo.getFirstLectureDate()).replace("星期", "每周"));
            }
            courseClass.setStudyingTime(importCourseClassVo.getTime());
            courseClass.setStartCourseTime(classLectureList.get(0).getClassTime());
            courseClass.setEndCourseTime(classLectureList.get(classLectureList.size() - 1).getClassTime());
            courseClass.setIsArrangeTeacher(StringUtils.isEmpty(importCourseClassVo.getTeacherName())?0:1);
            courseClass.setTeacherIds(null != teacherId ? String.valueOf(teacherId) : null);
            courseClass.setTeacherNames(teacherName);
            courseClass.setTeacherId(teacherId);
            courseClass.setTeacherName(teacherName);
            courseClass.setJobNature(jobNature);
            courseClass.setLockAmount(0);
            ClassTeacher classTeacher = new ClassTeacher();
            classTeacher.setClassId(courseClass.getClassId());
            classTeacher.setCreateTime(now);
            classTeacher.setUpdateTime(now);
            classTeacher.setRole(2);
            classTeacher.setTeacherId(teacherId);
            classTeacher.setTeacherName(teacherName);

            if (null != teacherId){
                classTeacherList.add(classTeacher);
            }

            courseClassList.add(courseClass);
        }

        insertBatch(courseClassList);
        classLectureService.insertBatch(allClassLectureList);
        if (classTeacherList.size() != 0){
            classTeacherService.insertBatch(classTeacherList);
        }

    }
    private List<ClassLecture> buildClassLecture(Date now, FullClassSaveVo fullClassSaveVo, CourseClass courseClass, Teacher teacher) {
        List<ClassLecture> classLectureList = new ArrayList<>(fullClassSaveVo.getLectureAmount());

        Date currentDate = fullClassSaveVo.getStartCourseTime();

        String classPeriod = fullClassSaveVo.getClassPeriod();
        String[] times = fullClassSaveVo.getStudyingTime().split("-");

        for (int i = 0; i < fullClassSaveVo.getLectureAmount(); i++) {
            ClassLecture classLecture = new ClassLecture();
            classLecture.setAttendanceStatus(0);
            classLecture.setLectureNo(i + 1);
            classLecture.setClassId(courseClass.getClassId());
            classLecture.setAbsenceAmount(0);
            classLecture.setAttendanceAmount(0);
            classLecture.setLateAmount(0);
            classLecture.setLeaveAmount(0);
            classLecture.setTotalAmount(0);
            classLecture.setCreateTime(now);
            classLecture.setUpdateTime(now);

            String day = Utils.formatDate(currentDate, "yyyy-MM-dd");
            while (StringUtils.isNotEmpty(fullClassSaveVo.getAvoidDate()) && fullClassSaveVo.getAvoidDate().contains(day)) {
                currentDate = nextClassDate(currentDate, classPeriod);
                day = Utils.formatDate(currentDate, "yyyy-MM-dd");
            }
            classLecture.setClassDate(currentDate);
            classLecture.setStartTime(times[0]);
            classLecture.setEndTime(times[1]);
            classLecture.setClassTime(Utils.parseDate(day + " " + times[0], "yyyy-MM-dd HH:mm"));

            if (teacher!=null){
                classLecture.setTeacherId(teacher.getTeacherId());
                classLecture.setTeacherName(teacher.getTeacherName());
            }

            classLectureList.add(classLecture);
            currentDate = nextClassDate(currentDate, classPeriod);
        }
        return classLectureList;
    }



    private List<ClassLecture> buildClassLecture(Date now, ImportCourseClassVo importCourseClassVo, CourseClass courseClass, Long teacherId, String teacherName) {
        List<ClassLecture> classLectureList = new ArrayList<>(importCourseClassVo.getLectureAmount());

        Date currentDate = importCourseClassVo.getFirstLectureDate();
        String excludeDays = importCourseClassVo.getExcludeDays();
        String classPeriod = importCourseClassVo.getClassPeriod();
        String[] times = importCourseClassVo.getTime().split("-");

        for (int i = 0; i < importCourseClassVo.getLectureAmount(); i++) {
            ClassLecture classLecture = new ClassLecture();
            classLecture.setAttendanceStatus(0);
            classLecture.setLectureNo(i + 1);
            classLecture.setClassId(courseClass.getClassId());
            classLecture.setAbsenceAmount(0);
            classLecture.setAttendanceAmount(0);
            classLecture.setLateAmount(0);
            classLecture.setLeaveAmount(0);
            classLecture.setTotalAmount(0);
            classLecture.setCreateTime(now);
            classLecture.setUpdateTime(now);

            String day = Utils.formatDate(currentDate, "yyyy-MM-dd");
            while (StringUtils.isNotEmpty(excludeDays) && excludeDays.contains(day)) {
                currentDate = nextClassDate(currentDate, classPeriod);
                day = Utils.formatDate(currentDate, "yyyy-MM-dd");
            }

            classLecture.setClassDate(currentDate);
            classLecture.setStartTime(times[0]);
            classLecture.setEndTime(times[1]);
            classLecture.setClassTime(Utils.parseDate(day + " " + times[0], "yyyy-MM-dd HH:mm"));

            classLecture.setTeacherName(teacherName);
            classLecture.setTeacherId(teacherId);

            classLectureList.add(classLecture);
            currentDate = nextClassDate(currentDate, classPeriod);
        }
        return classLectureList;
    }

    private Product createProduct(Date now, ImportCourseClassVo importCourseClassVo, AreaTeam areaTeam) {
        Product product = new Product();
        product.setName(importCourseClassVo.getProductName());
        product.setAreaTeamName(areaTeam.getName());
        product.setAreaTeamId(areaTeam.getAreaTeamId());
        product.setUpdateTime(now);
        product.setCreateTime(now);
        productService.insertSelective(product);
        return product;
    }

    private CourseTemplate createCourseTemplate(Date now, ImportCourseClassVo importCourseClassVo, AreaTeam areaTeam, BusTeam busTeam, CourseType courseType, BaseGrade baseGrade, BaseSubject baseSubject, Product product, Period period) {
        CourseTemplate courseTemplate = new CourseTemplate();
        courseTemplate.setBusTeamId(0L);
        courseTemplate.setBusTeamName(StringUtils.EMPTY);
        courseTemplate.setLevel(EnumUtils.valueOf(ClassLevelEnum.values(), importCourseClassVo.getLevel()).ordinal());
        courseTemplate.setQuota(importCourseClassVo.getQuota());
        courseTemplate.setStudyingFee(importCourseClassVo.getStudyingFee());
        courseTemplate.setMaterialFee(BigDecimal.ZERO);
        courseTemplate.setLectureDuration(importCourseClassVo.getLectureDuration());
        courseTemplate.setLectureAmount(importCourseClassVo.getLectureAmount());
        courseTemplate.setStatus(1);
        courseTemplate.setSubjectName(baseSubject.getSubjectName());
        courseTemplate.setSubjectId(baseSubject.getSubjectId());
        courseTemplate.setGradeId(baseGrade.getGradeId());
        courseTemplate.setGradeName(baseGrade.getGradeName());
        courseTemplate.setCourseTypeId(courseType.getCourseTypeId());
        courseTemplate.setCourseTypeName(courseType.getName());
        courseTemplate.setCourseName(importCourseClassVo.getCourseName());
        courseTemplate.setAreaTeamId(areaTeam.getAreaTeamId());
        courseTemplate.setAreaTeamName(areaTeam.getName());
        courseTemplate.setProductName(product.getName());
        courseTemplate.setProductId(product.getProductId());
        courseTemplate.setCreateTime(now);
        courseTemplate.setUpdateTime(now);
        courseTemplate.setPeriodName(period.getPeriodName());
        courseTemplate.setPeriodId(period.getPeriodId());
        courseTemplateService.insertSelective(courseTemplate);
        return courseTemplate;
    }

    private Date nextClassDate(Date currentDate, String classPeriod) {
        return DateUtils.addDays(currentDate, "每天".equals(classPeriod) ? 1 : "每周".equals(classPeriod) ? 7 : 0);
    }

    private void validateImportClass(List<ImportCourseClassVo> importCourseClassVoList) {
        String classPeriods = "每天、每周";
        String segments = "段次1、段次2、段次3、段次4、段次5";

        Pattern timePattern = Pattern.compile("^\\d{2}:\\d{2}-\\d{2}:\\d{2}$");

        for (ImportCourseClassVo importCourseClassVo : importCourseClassVoList) {
            if (StringUtils.isEmpty(importCourseClassVo.getClassName())) {
                throw new BusException("班级名称不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getGradeName())) {
                throw new BusException("年级不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getSubjectName())) {
                throw new BusException("科目不能为空");
            }
            if (importCourseClassVo.getLectureAmount() == null) {
                throw new BusException("讲数不能为空");
            }
            if (importCourseClassVo.getLectureDuration() == null) {
                throw new BusException("每一讲时长不能为空");
            }
            if (importCourseClassVo.getQuota() == null) {
                throw new BusException("学位不能为空");
            }
            if (importCourseClassVo.getStudyingFee() == null) {
                throw new BusException("学费不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getYear())) {
                throw new BusException("年份不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getSeason())) {
                throw new BusException("季节不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getClassPeriod())) {
                throw new BusException("上课周期不能为空");
            }
            if (!classPeriods.contains(importCourseClassVo.getClassPeriod())) {
                throw new BusException("上课周期有效值为：" + classPeriods);
            }

            if (importCourseClassVo.getFirstLectureDate() == null) {
                throw new BusException("首讲日期不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getTime())) {
                throw new BusException("首讲时间不能为空");
            }

            if (!timePattern.matcher(importCourseClassVo.getTime()).matches()) {
                throw new BusException("首讲时间格式不正确,正确格式为:08:30-10:20");
            }
            /*if(StringUtils.isEmpty(importCourseClassVo.getExcludeDays())){
                throw new BusException("规避日期不能为空");
            }*/
            if (StringUtils.isEmpty(importCourseClassVo.getAreaTeamName())) {
                throw new BusException("区域不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getBusTeamName())) {
                throw new BusException("业务组不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getLevel())) {
                throw new BusException("层次不能为空");
            }

            ClassLevelEnum classLevelEnum = EnumUtils.valueOf(ClassLevelEnum.values(), importCourseClassVo.getLevel());
            if (classLevelEnum == null) {
                throw new BusException("层次有效值为：" + EnumUtils.join(Arrays.copyOfRange(ClassLevelEnum.values(), 1, ClassLevelEnum.values().length)));
            }
            if (importCourseClassVo.getSegment() == null) {
                throw new BusException("段次不能为空");
            }
            if (!segments.contains(String.valueOf(importCourseClassVo.getSegment()))) {
                throw new BusException("段次有效值为：" + segments);
            }
            if (StringUtils.isEmpty(importCourseClassVo.getProductName())) {
                throw new BusException("产品名称不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getCourseName())) {
                throw new BusException("课程名不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getCourseType())) {
                throw new BusException("课程类型不能为空");
            }
            if (StringUtils.isEmpty(importCourseClassVo.getCampusName())) {
                throw new BusException("校区不能为空");
            }
        }
    }

    @Cacheable("CacheOfHowManySubjectForCampusAndPeriod")
    @Override
    public List<Long> howManySubjectForCampusAndPeriod(Long campusId, Long periodId) {
        return autoMapper.howManySubjectForCampusAndPeriod(campusId, periodId);
    }

    @Cacheable("CacheOfHowManyProductForBusTeam")
    @Override
    public List<Long> howManyProductForBusTeam(Long busTeamId) {
        return autoMapper.howManyProductForBusTeam(busTeamId);
    }

    @Cacheable(value = "CacheOfHowManyNowProductForBusTeam", key = "#busTeamId + '_' + #periodId")
    @Override
    public List<Long> howManyNowProductForBusTeam(Long busTeamId, List<Integer> statusList, Long periodId) {
        return autoMapper.howManyNowProductForBusTeam(busTeamId, statusList, periodId);
    }


    @Cacheable("CacheOfHowManySubjectIdGradeIdForBusTeam")
    @Override
    public List<String> howManySubjectIdGradeIdForBusTeam(Long busTeamId) {
        return autoMapper.howManySubjectIdGradeIdForBusTeam(busTeamId);
    }

    @Cacheable(value = "CacheOfHowManyNowSubjectIdGradeIdForBusTeam", key = "#busTeamId+'_'+#periodId")
    @Override
    public List<String> howManyNowSubjectIdGradeIdForBusTeam(Long busTeamId, List<Integer> statusList, Long periodId) {
        return autoMapper.howManyNowSubjectIdGradeIdForBusTeam(busTeamId, statusList, periodId);
    }


    @Override
    public Page<CourseClass> findCourseClassForRegByQueryForPage(CourseClassQueryVo courseClassQueryVo, int pageNo, int pageSize) {
        Example<CourseClass> example = CourseClass.createExample();
        courseClassQueryVo.setStatus(1);
        example.orderBy("segmentNo").orderBy("startCourseTime").asc();
        Example.Criteria criteria = example.createCriteria();
        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);
        if (courseClassQueryVo.getWeekNum() != null) {
            criteria.andCondition(" DAYOFWEEK(start_course_time) = " + courseClassQueryVo.getWeekNum());
        }
        return findPageByExample(example, pageNo, pageSize);
    }


    @Override
    public List<CourseClass> findListByBusTeamIdsPeriodIdsGradeIdsStatuses(List<Long> busTeamIds, List<Long> periodIds, List<Long> gradeIds, List<Integer> statuses, String... columns) {

        Example<CourseClass> example = CourseClass.createExample();
        Example.Criteria criteria = example.createCriteria();

        criteria.andIn("busTeamId", busTeamIds);
        criteria.andIn("periodId", periodIds);
        if (Utils.checkListNotEmpty(statuses)) {
            criteria.andIn("status", statuses);
        }
        if (Utils.checkListNotEmpty(gradeIds)) {
            criteria.andIn("gradeId", gradeIds);
        }

        example.selectProperties(columns);
        return findListByExample(example);

    }

    @Override
    public void updateEndCourseStatus() {
        autoMapper.updateEndCourseStatus();
    }

    @Override
    public void clearTeacher(Long classId) {
        autoMapper.clearTeacher(classId);
    }

    @Override
    public void updateCampusNameByCampusId(Long campusId, String campusName) {
        if (campusId != null) {
            Example<CourseClass> example = CourseClass.createExample();
            CourseClass courseClass = new CourseClass();
            courseClass.setCampusName(campusName);
            courseClass.setUpdateTime(TimeUtils.now());
            example.createCriteria().andEqualTo("campusId", campusId);
            this.updateSelectiveByExample(courseClass, example);
        }
    }

    @Override
    public void updateRoomNameByRoomId(Long roomId, String roomName) {
        if (roomId != null) {
            Example<CourseClass> example = CourseClass.createExample();
            CourseClass courseClass = new CourseClass();
            courseClass.setRoomName(roomName);
            courseClass.setUpdateTime(TimeUtils.now());
            example.createCriteria().andEqualTo("roomId", roomId);
            this.updateSelectiveByExample(courseClass, example);
        }
    }

    @Override
    public Page<CourseClass> findCanChangeClassPage(long classId, CourseClassQueryVo courseClassQueryVo, int beginClassLectureNo, int endClassLectureNo, int pageNo, int pageSize) {
        courseClassQueryVo.setBigOrEqualLectureAmount(endClassLectureNo);
        courseClassQueryVo.setLessCompletedLectureAmount(beginClassLectureNo);
        courseClassQueryVo.setStatus(1);
        Example<CourseClass> courseClassExample = CourseClass.createExample();
        courseClassExample.selectProperties(CourseClass.BASE_FIELDS);

        Example.Criteria criteria = courseClassExample.createCriteria();

        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);

        criteria.andNotEqualTo("classId", classId);

       /* List<CourseClass> courseClassList=this.findCourseClassForRegByQueryForList(courseClassQueryVo);
        List<Long> classIds = BeanUtils.toList(courseClassList, "classId");
        List<ClassLecture> classLectureList=classLectureService.findClassLectureByClassIdsLectureNo(classIds,beginClassLectureNo,0);
        Map<Long, ClassLecture> classLectureMap = BeanUtils.toMap(classLectureList, "classId");
        List<Long> realCoureClassId=new ArrayList<>(courseClassList.size());
        for (CourseClass tempClass:courseClassList){
            ClassLecture classLecture=classLectureMap.get(tempClass.getClassId());
            if (classLecture!=null){
                realCoureClassId.add(tempClass.getClassId());
            }
        }
        Example<CourseClass> courseClassExample=CourseClass.createExample();
        courseClassExample.selectProperties(CourseClass.BASE_FIELDS);
        courseClassExample.createCriteria().andIn("classId",realCoureClassId);

        return  findPageByExample(courseClassExample,pageNo,pageSize);*/
        return findPageByExample(courseClassExample, pageNo, pageSize);
    }

    @Override
    public void mergeDegree(Long classId) {
        this.autoMapper.mergeDegree(classId);
    }

    @Override
    public List<BusTeamPeriodGradeClassNumVo> findBusTeamPeriodGradeClassNum(SimpleQueryVo simpleQueryVo, int begin, int pageSize) {
        return this.autoMapper.findBusTeamPeriodGradeClassNum(simpleQueryVo, begin, pageSize);
    }

    @Override
    public Integer countBusTeamPeriodGradeClassNum(SimpleQueryVo simpleQueryVo) {
        return this.autoMapper.countBusTeamPeriodGradeClassNum(simpleQueryVo);
    }


    @Override
    public SXSSFWorkbook exportScheduleDataOfTeacher(List<TeacherScheduleVo> teacherScheduleVoList, Map<String,Integer> startClassDateMap,Map<String,Integer> weekMap,Map<Long,Integer> periodSegmentOrWeek) {
       return scheduleDataOfTeacher2Excel(teacherScheduleVoList,startClassDateMap,weekMap,periodSegmentOrWeek);
    }

    public static SXSSFWorkbook scheduleDataOfTeacher2Excel(List<TeacherScheduleVo> teacherScheduleVoList, Map<String,Integer> startClassDateMap,Map<String,Integer> weekMap,Map<Long,Integer> periodSegmentOrWeek) {

        SXSSFWorkbook excel = new SXSSFWorkbook();
        SXSSFSheet sheet = excel.createSheet("老师课表");
        SXSSFRow firstRow = sheet.createRow(0);
        List<String> titles=new ArrayList<>();
        titles.add("班级科目");
        titles.add("老师");
        titles.add("属性");
        titles.add("时间");

        if ( startClassDateMap!=null){
            Iterator<String>   starClasDateIterator= startClassDateMap.keySet().iterator();
            while(starClasDateIterator.hasNext()) {
                String key=starClasDateIterator.next();
                titles.add(key);
            }
        }
        if ( weekMap!=null){
            Iterator<String> weekIterator = weekMap.keySet().iterator();
            while(weekIterator.hasNext()) {
                String key=weekIterator.next();
                titles.add(key);
            }
        }



        for (int i = 0; i < titles.size(); i++) {
            firstRow.createCell(i).setCellValue(titles.get(i));
        }
        int rowNum=1;
        if (teacherScheduleVoList!=null){
            for (TeacherScheduleVo teacherScheduleVo:teacherScheduleVoList){
                int cellNum = 0;
                SXSSFRow row = sheet.createRow(rowNum++);

                SXSSFCell cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(teacherScheduleVo.getSubjectName()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(teacherScheduleVo.getTeacherName()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(EnumUtils.getName(JobNatureEnum.values() ,teacherScheduleVo.getJobNature()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(teacherScheduleVo.getTime()));




                List<CourseClass> courseClassList = teacherScheduleVo.getList();
                if (courseClassList != null && courseClassList.size() > 0) {
                    for (CourseClass courseClass : courseClassList) {
                        Long periodId = courseClass.getPeriodId();
                        int addNum = 0;
                        if (periodSegmentOrWeek.containsKey(periodId) && periodSegmentOrWeek.get(periodId) == 0) {
                            addNum = weekMap.get(weekNameArray[TimeUtils.getWeekOfDate(courseClass.getStartCourseTime())]) - 1;
                        } else if (periodSegmentOrWeek.containsKey(periodId) && periodSegmentOrWeek.get(periodId) == 1) {
                            String startClassDate=courseClass.getStartCourseTime()==null?"-":Utils.formatDate(courseClass.getStartCourseTime(),"yyyy-MM-dd");
                            addNum = startClassDateMap.get(startClassDate) - 1;
                        }
                        cell = row.getCell(cellNum + addNum);
                        if (cell == null) {
                            cell = row.createCell(cellNum + addNum);
                        }
                        String cellString = (StringUtils.isEmpty(cell.getStringCellValue()) ? "" : (cell.getStringCellValue() + ",")) + StringUtils.defaultString(courseClass.getCampusName()).replace("教学中心", "") + "+" +courseClass.getClassNo()+ courseClass.getGradeName() + courseClass.getClassName() + "#" + (courseClass.getRegAmount() == null ? 0 : courseClass.getRegAmount());
                        ;
                        cell.setCellValue(cellString);

                    }

                }
            }
        }

        return excel;
    }


    @Override
    public void copyInitOtherClassByOne(Long classId) {
        CourseClass courseClass=this.findById(classId);
        CourseClass other=new CourseClass();
        BeanUtils.copyProperties(other,courseClass);
        other.setClassId(null);
        other.setRegAmount(0);
        other.setOpenRegTime(null);
        other.setTeacherIds(null);
        other.setTeacherNames(null);
        other.setSeniorId(null);
        other.setSeniorName(null);
        other.setRoomId(null);
        other.setRoomName(null);
        other.setIsArrangeRoom(0);
        other.setIsArrangeTime(0);
        other.setIsArrangeTeacher(0);
        other.setStartCourseTime(null);
        other.setEndCourseTime(null);
        other.setProgressStatus(0);
        other.setCompletedLectureAmount(0);
        other.setCreateTime(TimeUtils.now());
        other.setUpdateTime(TimeUtils.now());
        other.setStatus(0);
        other.setStudyingTime(null);
        other.setClassNo(createClassNo());
        other.setClassDateTip(null);
        other.setTeacherId(null);
        other.setTeacherName(null);
        other.setJobNature(null);
        this.insert(other);

    }

    @Override
    public List<CourseClass> findCourseClassListWithOutPermission(CourseClassQueryVo courseClassQueryVo, String... columns) {
        Example<CourseClass> example = CourseClass.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();

        CriteriaUtils.fillCondition(criteria, courseClassQueryVo);

        if (columns != null) {
            example.selectProperties(columns);
        }

        return findListByExample(example);
    }

    @Override
    public boolean decreaseLockAmount(List<Long> classIds) {
        if(classIds == null || classIds.isEmpty() ){
            return false;
        }
        return autoMapper.decreaseLockAmount(classIds) == classIds.size() ;
    }

    @Override
    public boolean increaseLockAmount(List<Long> classIds) {
        return autoMapper.increaseLockAmount(classIds) == classIds.size();
    }

    public List<CourseClass> findSameClass(long periodId, long busTeamId, long gradeId, long subjectId, int level,String ...columns) {
        Example<CourseClass> example=CourseClass.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andEqualTo("periodId",periodId);
        criteria.andEqualTo("busTeamId",busTeamId);
        criteria.andEqualTo("gradeId",gradeId);
        criteria.andEqualTo("subjectId",subjectId);
        criteria.andEqualTo("level",level);
        criteria.andIn("status",Arrays.asList(0,1));
        return this.findListByExample(example);
    }

    @Override
    @Transactional
    public CourseClass saveClassByFullMessage(FullClassSaveVo fullClassSaveVo) {
        Date now=TimeUtils.now();
        CourseTemplate courseTemplate=courseTemplateService.findById(fullClassSaveVo.getCourseTemplateId());
        Period period=periodService.findById(courseTemplate.getPeriodId());
        BusTeam busTeam=busTeamService.findById(fullClassSaveVo.getBusTeamId());
        Campus campus=campusService.findById(fullClassSaveVo.getCampusId());
        Teacher teacher=null;
        if (fullClassSaveVo.getTeacherId()!=null){
            teacher=teacherService.findById(fullClassSaveVo.getTeacherId());
        }
        CourseClass courseClass = new CourseClass();
        BeanUtils.copyProperties(courseClass, courseTemplate);

        courseClass.setClassId(IdWorker.getId());
        courseClass.setStatus(0);
        courseClass.setIsArrangeTime(0);
        courseClass.setIsArrangeRoom(0);
        courseClass.setIsArrangeTeacher(0);
        courseClass.setClassNo(createClassNo());
        courseClass.setRegAmount(0);
        courseClass.setProgressStatus(0);
        courseClass.setStudyingFee(fullClassSaveVo.getStudyingFee());
        courseClass.setLectureAmount(fullClassSaveVo.getLectureAmount());
        courseClass.setLectureDuration(fullClassSaveVo.getLectureDuration());
        courseClass.setLevel(fullClassSaveVo.getLevel());
        courseClass.setClassName(fullClassSaveVo.getClassName());
        courseClass.setClassAliasName(StringUtils.isNotEmpty(fullClassSaveVo.getClassAliasName())?fullClassSaveVo.getClassAliasName():fullClassSaveVo.getClassName());
        courseClass.setUpdateTime(now);
        courseClass.setCreateTime(now);
        courseClass.setCompletedLectureAmount(0);
        courseClass.setClassType(0);
        courseClass.setPeriodId(period.getPeriodId());
        courseClass.setPeriodName(period.getPeriodName());
        courseClass.setQuota(fullClassSaveVo.getQuota());
        courseClass.setSegmentNo(fullClassSaveVo.getSegmentNo());
        courseClass.setIsRecommend(0);
        courseClass.setBusTeamName(busTeam.getName());
        courseClass.setBusTeamId(busTeam.getBusTeamId());
        courseClass.setCampusId(campus.getCampusId());
        courseClass.setCampusName(campus.getCampusName());

        List<ClassLecture> classLectureList = buildClassLecture(now, fullClassSaveVo, courseClass, teacher);

        courseClass.setIsArrangeTime(1);
        if ("每天".equals(fullClassSaveVo.getClassPeriod())) {
            courseClass.setClassDateTip(fullClassSaveVo.getClassPeriod());
        } else if ("每周".equals(fullClassSaveVo.getClassPeriod())) {
            courseClass.setClassDateTip(new SimpleDateFormat("E", Locale.CHINA).format(fullClassSaveVo.getStartCourseTime()).replace("星期", "每周"));
        }
        courseClass.setStudyingTime(fullClassSaveVo.getStudyingTime());
        courseClass.setStartCourseTime(classLectureList.get(0).getClassTime());
        courseClass.setEndCourseTime(classLectureList.get(classLectureList.size() - 1).getClassTime());
        if (teacher!=null){
            courseClass.setIsArrangeTeacher(1);
            courseClass.setTeacherIds(teacher.getTeacherId().toString());
            courseClass.setTeacherNames(teacher.getTeacherName());
            courseClass.setTeacherId(teacher.getTeacherId());
            courseClass.setTeacherName(teacher.getTeacherName());
            courseClass.setJobNature(teacher.getJobNature());
            ClassTeacher classTeacher = new ClassTeacher();
            classTeacher.setClassId(courseClass.getClassId());
            classTeacher.setCreateTime(now);
            classTeacher.setUpdateTime(now);
            classTeacher.setRole(2);
            classTeacher.setTeacherId(teacher.getTeacherId());
            classTeacher.setTeacherName(teacher.getTeacherName());
            classTeacherService.insertSelective(classTeacher);
        }
        this.insertSelective(courseClass);
        classLectureService.insertBatch(classLectureList);
        return courseClass;
    }

    @Override
    public List<CourseClass> findClassListByAreaTeamIdPeriodId(long areaTeamId, long periodId,String ...columns) {
        Example<CourseClass> example=CourseClass.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andEqualTo("periodId",periodId);
        criteria.andEqualTo("areaTeamId",areaTeamId);
        criteria.andIn("status",Arrays.asList(0,1,3));
        if (columns!=null){
            example.selectProperties(columns);
        }
        return this.findListByExample(example);
    }
}